import 'package:core_ui/net/http_callback.dart';
import 'package:core_ui/net/request.dart';
import 'package:dio/dio.dart';

class Http {
  late Dio _dio;

  Http._internal([BaseOptions? options, List<Interceptor>? interceptors]) {
    options ??= BaseOptions();
    _dio = Dio(options);
    if (null != interceptors && interceptors.isNotEmpty) {
      _dio.interceptors.addAll(interceptors);
    }
  }

  static final Http _instance = Http._internal();

  factory Http() => _instance;

  //===Desc:=====================================================================================

  void init(
    String baseUrl, {
    int? connectTimeout,
    int? receiveTimeout,
    int? sendTimeout,
    Map<String, dynamic>? queryParameters,
    Map<String, dynamic>? headers,
    List<Interceptor>? interceptors,
  }) {
    if (baseUrl.isEmpty) {
      throw Exception("The base url is empty,please check it");
    }
    _dio.options = _dio.options.copyWith(
      baseUrl: baseUrl,
      connectTimeout: connectTimeout,
      receiveTimeout: receiveTimeout,
      sendTimeout: sendTimeout,
      queryParameters: queryParameters,
      headers: headers,
    );
    if (interceptors != null && interceptors.isNotEmpty) {
      _dio.interceptors.addAll(interceptors);
    }
  }

  //===Desc:=====================================================================================
  void get<T>(
    NetRequest request, {
    Options? requestOptions,
    ProgressCallback? onReceiveProgress,
    OnSuccess<T>? onSuccess,
    OnError? onError,
  }) {
    String? baseUrl = request.baseUrl;
    String oldBaseUrl = "";
    bool isResetBaseUrl = false;
    if (null != baseUrl && baseUrl.isNotEmpty) {
      oldBaseUrl = _dio.options.baseUrl;
      _dio.options.baseUrl = baseUrl;
      isResetBaseUrl = true;
    }
    String? path = request.path;
    _dio
        .get<T>(
      path,
      queryParameters: request.parameters?.toMap(),
      options: requestOptions,
      onReceiveProgress: onReceiveProgress,
      cancelToken: request.cancelToken,
    )
        .then((value) {
      if (isResetBaseUrl) {
        _dio.options.baseUrl = oldBaseUrl;
      }
      onSuccess?.call(value);
    }).catchError((error) {
      if (isResetBaseUrl) {
        _dio.options.baseUrl = oldBaseUrl;
      }
      if (error is DioError) {
        onError?.call(error);
      } else {
        onError?.call(DioError(
          requestOptions: RequestOptions(
            path: path,
            baseUrl: _dio.options.baseUrl,
            method: _dio.options.method,
          ),
          error: error,
          type: DioErrorType.other,
        ));
      }
    });
  }

  void postFormData<T>(
    NetRequest request, {
    Options? requestOptions,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
    OnSuccess<T>? onSuccess,
    OnError? onError,
  }) {
    String? baseUrl = request.baseUrl;
    String oldBaseUrl = "";
    bool isResetBaseUrl = false;
    if (null != baseUrl && baseUrl.isNotEmpty) {
      oldBaseUrl = _dio.options.baseUrl;
      _dio.options.baseUrl = baseUrl;
      isResetBaseUrl = true;
    }
    String? path = request.path;
    _dio
        .post<T>(
      path,
      data:
          FormData.fromMap(request.parameters?.toMap() ?? <String, dynamic>{}),
      options: requestOptions,
      onSendProgress: onSendProgress,
      onReceiveProgress: onReceiveProgress,
      cancelToken: request.cancelToken,
    )
        .then((value) {
      if (isResetBaseUrl) {
        _dio.options.baseUrl = oldBaseUrl;
      }
      onSuccess?.call(value);
    }).catchError((error) {
      if (isResetBaseUrl) {
        _dio.options.baseUrl = oldBaseUrl;
      }
      if (error is DioError) {
        onError?.call(error);
      } else {
        onError?.call(DioError(
          requestOptions: RequestOptions(
            path: path,
            baseUrl: _dio.options.baseUrl,
            method: _dio.options.method,
          ),
          error: error,
          type: DioErrorType.other,
        ));
      }
    });
  }

  void postJson<T>(
    NetRequest request, {
    Options? requestOptions,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
    OnSuccess<T>? onSuccess,
    OnError? onError,
  }) {
    String? baseUrl = request.baseUrl;
    String oldBaseUrl = "";
    bool isResetBaseUrl = false;
    if (null != baseUrl && baseUrl.isNotEmpty) {
      oldBaseUrl = _dio.options.baseUrl;
      _dio.options.baseUrl = baseUrl;
      isResetBaseUrl = true;
    }
    String? path = request.path;
    _dio
        .post<T>(
      path,
      data: request.parameters?.toMap(),
      options: requestOptions,
      onSendProgress: onSendProgress,
      onReceiveProgress: onReceiveProgress,
      cancelToken: request.cancelToken,
    )
        .then((value) {
      if (isResetBaseUrl) {
        _dio.options.baseUrl = oldBaseUrl;
      }
      onSuccess?.call(value);
    }).catchError((error) {
      if (isResetBaseUrl) {
        _dio.options.baseUrl = oldBaseUrl;
      }
      if (error is DioError) {
        onError?.call(error);
      } else {
        onError?.call(DioError(
          requestOptions: RequestOptions(
            path: path,
            baseUrl: _dio.options.baseUrl,
            method: _dio.options.method,
          ),
          error: error,
          type: DioErrorType.other,
        ));
      }
    });
  }

  Future<Response> download(String url, String savePath,
      {dynamic data,
      Map<String, dynamic>? queryParameters,
      Options? requestOptions,
      bool deleteOnError = true,
      String lengthHeader = Headers.contentLengthHeader,
      ProgressCallback? onReceiveProgress,
      CancelToken? cancelToken}) async {
    Response response = await _dio.download(url, savePath,
        data: data,
        queryParameters: queryParameters,
        options: requestOptions,
        deleteOnError: deleteOnError,
        lengthHeader: lengthHeader,
        onReceiveProgress: onReceiveProgress,
        cancelToken: cancelToken);
    return response;
  }
}
